package game.server.net;

import game.common.net.GameHandler;
import game.server.world.GameObject;
import game.server.world.GameObjectVisitor;
import game.server.world.GameWorld;

import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.util.Map;
import java.util.TreeMap;

import org.xsocket.MaxReadSizeExceededException;
import org.xsocket.connection.IConnectHandler;
import org.xsocket.connection.IDisconnectHandler;
import org.xsocket.connection.INonBlockingConnection;

public class TestGameConnectHandler extends GameHandler implements IConnectHandler{
	private int totalClients;
	
	private GameWorld world;
	
	private Map<String,INonBlockingConnection> connections = new TreeMap<String, INonBlockingConnection>();
	
	public TestGameConnectHandler(GameWorld world) {
		this.world = world;
	}

	@Override
	public boolean onConnect(INonBlockingConnection nbc) throws IOException,BufferUnderflowException, MaxReadSizeExceededException { 
		String pName = ("Player" + ++totalClients); 

		connections.put(pName, nbc);
		
		// creates the new game object
		GameObject obj = new GameObject(pName);

		// attaches the new session
		GameSession gs = new GameSession();
		gs.setPlayerName(pName);
		gs.setGameObject(obj);
		nbc.setAttachment(gs);

		System.out.println("incoming " + pName);
		
		// adds object in the world
		world.addObject(obj);
		
		nbc.setAutoflush(false);
		
		// sends name and position
		nbc.write((short) PTYPE_TEST_FIRST);
		nbc.write((short) (sizeOfPlayerName() + sizeOfVector()));
		writePlayerName(pName, nbc);
		writeVector(obj,nbc);
		nbc.flush();
		
		// notify clients
		notifyAfterPlayerIncoming(obj);
		
		nbc.setHandler(new InGameDataHandler(world, connections));
		
		return true;
	}
	
	private void notifyAfterPlayerIncoming(GameObject obj){
		world.visitObjectsAtRange(obj.getXf(), obj.getYf(), 1000, new IncomingPlayerObjectVisitor(obj));
	}
	
	class IncomingPlayerObjectVisitor implements GameObjectVisitor{
		private short packetSize = (short) (sizeOfPlayerName() + sizeOfVector());
		
		private GameObject incomingPlayer;
		private INonBlockingConnection incomingPlayerConnection;

		private String incomingPlayerName;
		
		public IncomingPlayerObjectVisitor(GameObject incomingPlayer) {
			this.incomingPlayer = incomingPlayer;
			this.incomingPlayerName = incomingPlayer.getObjectName();
			this.incomingPlayerConnection = connections.get(this.incomingPlayerName);
		}
		
		@Override
		public void visit(GameObject obj) {
			
			String objectName = obj.getObjectName();
			INonBlockingConnection nbc = connections.get(objectName);
			
			// send new player to the not far player
			try {
				synchronized(nbc){
					nbc.write(PTYPE_UPDATE_OBJECT_POSITION);
					nbc.write(packetSize);
					writePlayerName(this.incomingPlayerName, nbc);
					writeVector(this.incomingPlayer, nbc);
					nbc.flush();
				}
				
			} catch (BufferOverflowException e){
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			// send the not far player to the new player
			try {
				synchronized(this.incomingPlayerConnection){
					this.incomingPlayerConnection.write(PTYPE_UPDATE_OBJECT_POSITION);
					this.incomingPlayerConnection.write(packetSize);
					writePlayerName(objectName, this.incomingPlayerConnection);
					writeVector(obj, this.incomingPlayerConnection);
					this.incomingPlayerConnection.flush();
				}
				
			} catch (BufferOverflowException e){
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
